

package com.yiqixuejava.reconciliation.util;

import org.apache.commons.lang.time.DateFormatUtils;

import java.net.InetAddress;
import java.net.NetworkInterface;
import java.net.SocketException;
import java.net.UnknownHostException;
import java.util.Enumeration;

import static java.net.InetAddress.getLocalHost;

/**
 * 与snowflake算法区别,返回字符串id
 *
 * @Project concurrency
 * Created by wgy on 16/7/19.
 */
public enum IdGenerator {

    INSTANCE;
    public static final String ip;
    private long sequence = 0L;
    private long sequenceBits = 12L; //序列号12位
    private long sequenceMask = -1L ^ (-1L << sequenceBits); //4095
    private long lastTimestamp = -1L;

    IdGenerator(){

    }
    static {
        ip = getLocalIP();
    }


    public synchronized String nextId() {
        long timestamp = timeGen(); //获取当前毫秒数
        //如果服务器时间有问题(时钟后退) 报错。
        if (timestamp < lastTimestamp) {
            throw new RuntimeException(String.format(
                    "Clock moved backwards.  Refusing to generate id for %d milliseconds", lastTimestamp - timestamp));
        }
        //如果上次生成时间和当前时间相同,在同一毫秒内
        if (lastTimestamp == timestamp) {
            //sequence自增，因为sequence只有12bit，所以和sequenceMask相与一下，去掉高位
            sequence = (sequence + 1) & sequenceMask;
            //判断是否溢出,也就是每毫秒内超过4095，当为4096时，与sequenceMask相与，sequence就等于0
            if (sequence == 0) {
                timestamp = tilNextMillis(lastTimestamp); //自旋等待到下一毫秒
            }
        } else {
            sequence = 0L; //如果和上次生成时间不同,重置sequence，就是下一毫秒开始，sequence计数重新从0开始累加
        }
        lastTimestamp = timestamp;
        long suffix =  sequence;
        String suffixStr =String.valueOf(suffix);
//        while(suffixStr.length() < 4){
//            suffixStr = "0" + suffixStr ;
//        }
        //yyyy-MM-dd\'T\'HH:mm:ssZZ ,linux必须是标准的符号
        String datePrefix = DateFormatUtils.format(timestamp, "yyyyMMddHHmmssSSS");

        return datePrefix + ip +  suffixStr;
    }

    protected long tilNextMillis(long lastTimestamp) {
        long timestamp = timeGen();
        while (timestamp <= lastTimestamp) {
            timestamp = timeGen();
        }
        return timestamp;
    }

    protected long timeGen() {
        return System.currentTimeMillis();
    }

    private String getLastIP(){
        String lastip = null;
        try{
           lastip = getLocalHost().getHostAddress();
            String[] split = lastip.split("\\.");
            lastip = split[split.length-1];
        } catch (UnknownHostException e) {
            e.printStackTrace();
        }
        return lastip;
    }

    public static String getLocalIP() {
        String lastip = null;
        try{
          if (isWindowsOS()) {
             lastip =  InetAddress.getLocalHost().getHostAddress();
            } else {
              lastip = getLinuxLocalIp();
            }
            String[] split = lastip.split("\\.");
            lastip = split[split.length-1];
        } catch (Exception e) {
            e.printStackTrace();
            System.out.println("获取Ip异常");
        }
        while (lastip.length()<3){
            lastip = "0"+lastip;
        }

        return lastip;
    }

    private static String getLinuxLocalIp() throws SocketException {
        String ip = "";
        try {
            for (Enumeration<NetworkInterface> en = NetworkInterface.getNetworkInterfaces(); en.hasMoreElements();) {
                NetworkInterface intf = en.nextElement();
                String name = intf.getName();
                if (!name.contains("docker") && !name.contains("lo")) {
                    for (Enumeration<InetAddress> enumIpAddr = intf.getInetAddresses(); enumIpAddr.hasMoreElements();) {
                        InetAddress inetAddress = enumIpAddr.nextElement();
                        if (!inetAddress.isLoopbackAddress()) {
                            String ipaddress = inetAddress.getHostAddress().toString();
                            if (!ipaddress.contains("::") && !ipaddress.contains("0:0:") && !ipaddress.contains("fe80")) {
                                ip = ipaddress;
                                System.out.println(ipaddress);
                            }
                        }
                    }
                }
            }
        } catch (SocketException ex) {
            System.out.println("获取ip地址异常");
            ip = "127.0.0.1";
            ex.printStackTrace();
        }
        System.out.println("IP:"+ip);
        return ip;
    }

    public static boolean isWindowsOS() {
        boolean isWindowsOS = false;
        String osName = System.getProperty("os.name");
        if (osName.toLowerCase().indexOf("windows") > -1) {
            isWindowsOS = true;
        }
        return isWindowsOS;
    }



}